package com.zoe.onelink.business.ws;

import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.DefinedBy;
import lombok.SneakyThrows;

import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2023</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2023-02-14
 */
public class OnelinkJarFileManager extends JavacFileManager implements JavaFileManager {
    private URLClassLoader classLoader;

    OnelinkJarFileManager(URLClassLoader systemLoader, Context context) {
        super(context, true, null);
        this.classLoader = systemLoader;
    }

    @Override
    public ClassLoader getClassLoader(Location location) {
        return classLoader;
    }


    private List<JavaFileObject> find(String packageName) {
        List<JavaFileObject> result = new ArrayList<>();
        String javaPackageName = packageName.replaceAll("\\.", "/");
        try {
            Enumeration<URL> urls = classLoader.findResources(javaPackageName);
            while (urls.hasMoreElements()) {
                URL ll = urls.nextElement();
                String ext_form = ll.toExternalForm();
                String jar = ext_form.substring(0, ext_form.lastIndexOf("!"));
                String pkg = ext_form.substring(ext_form.lastIndexOf("!") + 1);

                JarURLConnection conn = (JarURLConnection) ll.openConnection();
                conn.connect();
                Enumeration<JarEntry> jar_items = conn.getJarFile().entries();
                while (jar_items.hasMoreElements()) {
                    JarEntry item = jar_items.nextElement();
                    if (item.isDirectory() || (!item.getName().endsWith(".class"))) {
                        continue;
                    }
                    if (item.getName().lastIndexOf("/") != (pkg.length() - 1)) {
                        continue;
                    }
                    String name = item.getName();
                    URI uri = URI.create(jar + "!/" + name);
                    String binaryName = name.replaceAll("/", ".");
                    binaryName = binaryName.substring(0, binaryName.indexOf(JavaFileObject.Kind.CLASS.extension));
                    result.add(new UriFileObject(binaryName, uri));
                    // loadClassInLaunchedClassLoader(binaryName);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    @SneakyThrows
    @Override
    public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
        Iterable<JavaFileObject> list = super.list(location, packageName, kinds, recurse);
        if (!(list == null || (!list.iterator().hasNext()))) {
            return list;
        }
        if (location == StandardLocation.PLATFORM_CLASS_PATH) {
            return list;
        }
        return find(packageName);
    }

    @Override
    @DefinedBy(DefinedBy.Api.COMPILER)
    public String inferBinaryName(Location location, JavaFileObject file) {
        try {
            return super.inferBinaryName(location, file);
        } catch (IllegalArgumentException e) {
            return ((UriFileObject) file).getBinaryName();
        }
    }
}